"""
数据分析模块的数据模型
"""
from datetime import datetime
from enum import Enum
from typing import Optional, List, Annotated, Union

from pydantic import BaseModel, Field, ConfigDict, field_validator, BeforeValidator

from app.schemas.alarm_schemas import empty_str_to_none


class GranularityType(str, Enum):
	"""统计粒度枚举"""
	HOUR = "hour"
	DAY = "day"
	MONTH = "month"


class AnalyticsGroupBy(str, Enum):
	"""统计分组枚举"""
	STATUS = "status"
	TYPE = "type"
	DAY = "day"
	DEVICE = "device"
	ALL = "ALL"


# ---------- 用量统计请求参数 ----------
class ConsumptionStatsRequest(BaseModel):
	"""用量统计请求参数"""
	station_id: Optional[int] = Field(None, description="台区ID")
	device_id: Optional[int] = Field(None, description="设备ID")
	start_date: datetime = Field(..., description="开始日期")
	end_date: datetime = Field(..., description="结束日期")
	granularity: GranularityType = Field(GranularityType.DAY, description="统计粒度")

	model_config = ConfigDict(from_attributes=True)

	@field_validator("end_date")
	def check_date_range(cls, v: datetime, info) -> datetime:
		if v <= info.data["start_date"]:
			raise ValueError("结束时间必须晚于开始时间")
		return v


# ---------- 用量统计响应数据 ----------
class ConsumptionStatsResponse(BaseModel):
	"""用量统计响应数据"""
	total_kwh: float = Field(..., description="总用电量")
	a_phase_kwh: float = Field(0.0, description="A相用电量")
	b_phase_kwh: float = Field(0.0, description="B相用电量")
	c_phase_kwh: float = Field(0.0, description="C相用电量")
	three_phase_kwh: float = Field(0.0, description="三相表总用电量")
	avg_daily_kwh: float = Field(0.0, description="日均用电量")
	max_demand_kw: float = Field(0.0, description="峰值功率")
	max_demand_time: Optional[datetime] = Field(None, description="峰值功率出现时间")

	model_config = ConfigDict(from_attributes=True)


# ---------- 告警事件统计请求参数 ----------
class AlarmStatsRequest(BaseModel):
	"""告警事件统计请求参数"""
	group_by: AnalyticsGroupBy = Field(None, description="分组方式")
	start_date: datetime = Field(..., description="开始日期")
	end_date: datetime = Field(..., description="结束日期")

	model_config = ConfigDict(from_attributes=True)

	@field_validator("end_date")
	def check_date_range(cls, v: datetime, info) -> datetime:
		if v <= info.data["start_date"]:
			raise ValueError("结束时间必须晚于开始时间")
		return v


# ---------- 告警事件统计响应数据 ----------
class AlarmStatsItem(BaseModel):
	"""告警统计项"""
	key: str = Field(..., description="分组键")
	count: int = Field(..., description="数量")

	model_config = ConfigDict(from_attributes=True)


class AlarmTrendItem(BaseModel):
	"""告警趋势项"""
	date: str = Field(..., description="日期")
	count: int = Field(..., description="数量")

	model_config = ConfigDict(from_attributes=True)


class AlarmTopDeviceItem(BaseModel):
	"""告警设备排名项"""
	meter_code: str = Field(..., description="电表编码")
	count: int = Field(..., description="告警数量")

	model_config = ConfigDict(from_attributes=True)


class AlarmStatsResponse(BaseModel):
	"""告警事件统计响应数据"""
	by_status: List[AlarmStatsItem] = Field([], description="按状态统计")
	by_type: List[AlarmStatsItem] = Field([], description="按类型统计")
	trend: List[AlarmTrendItem] = Field([], description="趋势统计")
	top_devices: List[AlarmTopDeviceItem] = Field([], description="设备排名")

	model_config = ConfigDict(from_attributes=True)


# ---------- 区域设备资产统计请求参数 ----------
class DeviceInventoryRequest(BaseModel):
	"""区域设备资产统计请求参数"""
	province_code: Annotated[Union[str, None], BeforeValidator(empty_str_to_none)] = Field(
		None, description="省份编码（空字符串将被视为None）"
	)
	city_code: Annotated[Union[str, None], BeforeValidator(empty_str_to_none)] = Field(
		None, description="城市编码（空字符串将被视为None）"
	)
	area_code: Annotated[Union[str, None], BeforeValidator(empty_str_to_none)] = Field(
		None, description="区县编码（空字符串将被视为None）"
	)

	model_config = ConfigDict(from_attributes=True)


# ---------- 区域设备资产统计响应数据 ----------
class DeviceInventoryResponse(BaseModel):
	"""区域设备资产统计响应数据"""
	total_stations: int = Field(0, description="台区总数")
	total_boxes: int = Field(0, description="电箱总数")
	total_rtus: int = Field(0, description="RTUS总数")
	total_meters: int = Field(0, description="电表总数")
	a_phase_meters: int = Field(0, description="A相电表数")
	b_phase_meters: int = Field(0, description="B相电表数")
	c_phase_meters: int = Field(0, description="C相电表数")
	three_phase_meters: int = Field(0, description="三相电表数")
	online_count: int = Field(0, description="在线设备数")
	offline_count: int = Field(0, description="离线设备数")
	abnormal_count: int = Field(0, description="异常设备数")

	model_config = ConfigDict(from_attributes=True)


# ---------- 设备用电量统计请求参数 ----------
class DeviceDailyConsumptionRequest(BaseModel):
	"""设备用电量统计请求参数"""
	serial_no: Optional[str] = Field(None, description="设备序列号", max_length=64)
	start_time: datetime = Field(None, description="开始时间")
	end_time: datetime = Field(None, description="结束时间")
	station_id: Optional[int] = Field(None, description="台区ID")

	model_config = ConfigDict(from_attributes=True)

	@field_validator("end_time")
	def check_date_range(cls, v: datetime, info) -> datetime:
		if v <= info.data["start_time"]:
			raise ValueError("结束时间必须晚于开始时间")
		return v


# ---------- 设备用电量统计响应数据 ----------
class DailyConsumptionItem(BaseModel):
	"""每日用电量项"""
	freeze_day: str = Field(..., description="冻结日期(YYYY-MM-DD)")
	total_kwh: float = Field(..., description="当日用电量(kWh)")

	model_config = ConfigDict(from_attributes=True)


class DeviceDailyConsumptionResponse(BaseModel):
	"""设备用电量统计响应数据"""
	serial_no: Optional[str] = Field(None, description="设备序列号（单设备查询时返回）")
	station_id: Optional[int] = Field(None, description="台区ID（按台区查询时返回）")
	total_days: int = Field(..., description="统计天数")
	total_consumption: float = Field(0.0, description="总用电量(kWh)")
	avg_daily_consumption: float = Field(0.0, description="日均用电量(kWh)")
	daily_data: List[DailyConsumptionItem] = Field([], description="每日用电量数据")

	model_config = ConfigDict(from_attributes=True)
